/*
 * @Author: your name
 * @Date: 2021-12-28 16:11:50
 * @LastEditTime: 2022-01-11 16:28:24
 * @LastEditors: your name
 * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * @FilePath: \vue\src\core\observer\array.js
 */
/**
 * 定义 arrayMethods 对象，用于增强 Array.prototype
 * 当访问 arrayMethods 对象上的那七个方法时会被拦截，以实现数组响应式
 */
import { def } from "../util/index";

// 备份 数组原型对象
const arrayProto = Array.prototype;
// 通过继承的方式创建新的 arrayMethods对象，它的原型是原始数组原型对象
export const arrayMethods = Object.create(arrayProto);
// 操作数组的七个方法，这七个方法可以改变数组自身
const methodsToPatch = [
  "push",
  "pop",
  "shift",
  "unshift",
  "splice",
  "sort",
  "reverse",
];

/**
 * 拦截变异方法并触发事件
 */
methodsToPatch.forEach(function (method) {
  // 缓存原生方法，比如 push
  const original = arrayProto[method];
  // def 就是 Object.defineProperty，拦截 arrayMethods.method 的访问
  def(arrayMethods, method, function mutator(...args) {
    // 先执行原生方法，比如 push.apply(this, args)
    //这里的this 指向的是调用方法的数组
    //this中肯定有__ob__ 因为数组不可能是第一次遍历，当递归遍历的时候为对象每个属性都添加__ob__ 值 及为Observe实例
    const result = original.apply(this, args);
    const ob = this.__ob__;
    let inserted;
    // 如果 method 是以下三个之一，说明是新插入了元素
    switch (method) {
      case "push":
      case "unshift":
        inserted = args;
        break;
      case "splice":
        inserted = args.slice(2);
        break;
    }
    // 对新插入的元素做响应式处理
    if (inserted) ob.observeArray(inserted);
    // 通知更新
    ob.dep.notify();
    return result;
  });
});
